package learn.juc;

import lombok.Data;
import lombok.extern.java.Log;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

@Log
public class DelayedQueueDemo {

    static class Product implements Runnable {
        private final BlockingQueue queue;

        Product(BlockingQueue queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            log.info("begin put");
            long beginTime = System.currentTimeMillis();
            try {
                // 延迟2s
                queue.put(new DelayedDTO(System.currentTimeMillis() + 2000L, beginTime));
                queue.put(new DelayedDTO(System.currentTimeMillis() + 5000L, beginTime));
                queue.put(new DelayedDTO(System.currentTimeMillis() + 10000L, beginTime));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Consumer implements Runnable {
        private final BlockingQueue queue;

        public Consumer(BlockingQueue queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                log.info("Consumer begin");
                ((DelayedDTO) queue.take()).run();
                ((DelayedDTO) queue.take()).run();
                ((DelayedDTO) queue.take()).run();
                log.info("Consumer end");
            } catch (InterruptedException e) {
                log.info("" + e);
            }
        }
    }

    @Data
    static class DelayedDTO implements Delayed, Runnable {
        Long s;
        Long beginTime;

        public DelayedDTO(Long s, Long beginTime) {
            this.s = s;
            this.beginTime = beginTime;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        }

        @Override
        public void run() {
            log.info("现在已经过了" + (System.currentTimeMillis() - beginTime) / 1000 + "秒钟");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BlockingQueue q = new DelayQueue();
        DelayedQueueDemo.Product p = new DelayedQueueDemo.Product(q);
        DelayedQueueDemo.Consumer c = new DelayedQueueDemo.Consumer(q);
        new Thread(c).start();
        new Thread(p).start();
    }
}

